﻿using System.Net;
using System.Text.RegularExpressions;

namespace Nop.Services.Html.CodeFormatter;

/// <summary>
/// Represents a code format helper
/// </summary>
public partial class CodeFormatHelper
{
    #region Fields

    protected static readonly Regex _regexHtml = new("<[^>]*>", RegexOptions.Compiled);

    protected static readonly Regex _regexCode = new(@"\[code\](?<inner>(.*?))\[/code\]", RegexOptions.Compiled | RegexOptions.IgnoreCase);

    #endregion

    #region Utilities

    /// <summary>
    /// Code evaluator method
    /// </summary>
    /// <param name="match">Match</param>
    /// <returns>Formatted text</returns>
    protected static string CodeEvaluatorSimple(Match match)
    {
        if (!match.Success)
            return match.Value;

        var options = new HighlightOptions
        {
            Language = "c#",
            Code = match.Groups["inner"].Value,
            DisplayLineNumbers = false,
            Title = string.Empty,
            AlternateLineNumbers = false
        };

        var result = match.Value;
        result = Highlight(options, result);
        return result;
    }

    /// <summary>
    /// Strips HTML
    /// </summary>
    /// <param name="html">HTML</param>
    /// <returns>Formatted text</returns>
    protected static string StripHtml(string html)
    {
        if (string.IsNullOrEmpty(html))
            return string.Empty;

        return _regexHtml.Replace(html, string.Empty);
    }

    /// <summary>
    /// Returns the formatted text.
    /// </summary>
    /// <param name="options">Whatever options were set in the regex groups.</param>
    /// <param name="text">Send the e.body so it can get formatted.</param>
    /// <returns>The formatted string of the match.</returns>
    protected static string Highlight(HighlightOptions options, string text)
    {
        switch (options.Language)
        {
            case "c#":
                var csf = new CSharpFormat
                {
                    LineNumbers = options.DisplayLineNumbers,
                    Alternate = options.AlternateLineNumbers
                };
                return WebUtility.HtmlDecode(csf.FormatCode(text));

            case "vb":
                var vbf = new VisualBasicFormat
                {
                    LineNumbers = options.DisplayLineNumbers,
                    Alternate = options.AlternateLineNumbers
                };
                return vbf.FormatCode(text);

            case "js":
                var jsf = new JavaScriptFormat
                {
                    LineNumbers = options.DisplayLineNumbers,
                    Alternate = options.AlternateLineNumbers
                };
                return WebUtility.HtmlDecode(jsf.FormatCode(text));

            case "html":
                var htmlf = new HtmlFormat
                {
                    LineNumbers = options.DisplayLineNumbers,
                    Alternate = options.AlternateLineNumbers
                };
                text = StripHtml(text).Trim();
                var code = htmlf.FormatCode(WebUtility.HtmlDecode(text)).Trim();
                return code.Replace("\r\n", "<br />").Replace("\n", "<br />");

            case "xml":
                var xmlf = new HtmlFormat
                {
                    LineNumbers = options.DisplayLineNumbers,
                    Alternate = options.AlternateLineNumbers
                };
                text = text.Replace("<br />", "\r\n");
                text = StripHtml(text).Trim();
                var xml = xmlf.FormatCode(WebUtility.HtmlDecode(text)).Trim();
                return xml.Replace("\r\n", "<br />").Replace("\n", "<br />");

            case "tsql":
                var tsqlf = new TsqlFormat
                {
                    LineNumbers = options.DisplayLineNumbers,
                    Alternate = options.AlternateLineNumbers
                };
                return WebUtility.HtmlDecode(tsqlf.FormatCode(text));

            case "msh":
                var mshf = new MshFormat
                {
                    LineNumbers = options.DisplayLineNumbers,
                    Alternate = options.AlternateLineNumbers
                };
                return WebUtility.HtmlDecode(mshf.FormatCode(text));
        }

        return string.Empty;
    }

    #endregion

    #region Methods

    /// <summary>
    /// Formats the text
    /// </summary>
    /// <param name="text">Text</param>
    /// <returns>Formatted text</returns>
    public static string FormatTextSimple(string text)
    {
        if (string.IsNullOrEmpty(text))
            return string.Empty;

        if (!text.Contains("[/code]"))
            return text;

        text = _regexCode.Replace(text, CodeEvaluatorSimple);
        text = _regexCode.Replace(text, "$1");
        return text;
    }

    #endregion
}